Security News
GitHub Removes Malicious Pull Requests Targeting Open Source Repositories
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Forgo is a 4KB library that makes it super easy to create modern web apps using JSX (like React).
Forgo is a 4KB library that makes it super easy to create modern web apps using JSX (like React).
Unlike React, there are very few framework specific patterns and lingo to learn. Everything you already know about DOM APIs and JavaScript will easily carry over.
All of Forgo is in one small JS file (actually it's TypeScript). It is a goal of the project is to remain within that single file.
npm i forgo
An easy way to get a project started is by cloning one of the following templates. These templates use parcel as the bundler/build tool.
A Forgo Component is a function that returns an object with a render() function. The render function is called for the first render, and then subsequently for each rerender.
import { rerender } from "forgo";
function SimpleTimer() {
let seconds = 0; // Look ma no useState
return {
render(props, args) {
setTimeout(() => {
seconds++;
rerender(args.element); // rerender!
}, 1000);
return <div>{seconds} secs have elapsed...</div>;
},
};
}
Use the mount() function once your document has loaded.
import { mount } from "forgo";
window.addEventListener("load", () => {
mount(<SimpleTimer />, document.getElementById("root"));
});
You could also pass a selector instead of an element.
window.addEventListener("load", () => {
mount(<SimpleTimer />, "#root");
});
That works just as you'd have seen in React.
function Parent(props) {
return {
render(props, args) {
return (
<div>
<Greeter firstName="Jeswin" />
<Greeter firstName="Kai" />
</div>
);
},
};
}
function Greeter(props) {
return {
render(props, args) {
return <div>Hello {props.firstName}</div>;
},
};
}
You can access and read form input elements using regular DOM APIs.
Like this:
function Component(props) {
const myInputRef = {};
return {
render(props, args) {
function onClick() {
const inputElement = document.getElementById("myinput");
alert(inputElement.value); // Read the text input!
}
return (
<div>
<input type="text" id="myinput" />
<button onclick={onClick}>Click me!</button>
</div>
);
},
};
}
But there's also another way to do this, without requiring you to assign an id. An object referenced by the ref attribute in an element's markup will have its value property set to the actual DOM element.
So you could do this as well:
function Component(props) {
const myInputRef = {};
return {
render(props, args) {
function onClick() {
const inputElement = myInputRef.value;
alert(inputElement.value); // Read the text input!
}
return (
<div>
<input type="text" ref={myInputRef} />
<button onclick={onClick}>Click me!</button>
</div>
);
},
};
}
When a component is unmounted, Forgo will invoke the unmount() function if defined for a component. It receives the current props and args as arguments, just as in the render() function.
function Greeter(props) {
return {
render(props, args) {
return <div>Hello {props.firstName}</div>;
},
unmount(props, args) {
console.log("Got unloaded.");
},
};
}
You'd rarely have to use this. mount() gets called with the same arguments as render () but after getting mounted on a real DOM node. At this point you can expect args.element.node to be populated, where args is the second parameter to mount() and render().
function Greeter(props) {
return {
render(props, args) {
return <div id="hello">Hello {props.firstName}</div>;
},
mount(props, args) {
console.log(`Mounted on node with id ${args.element.node.id}`);
},
};
}
When the shouldUpdate() function is defined for a component, Forgo will call it with newProps and oldProps and check if the return value is true before rendering the component. Returning false will skip rendering the component.
function Greeter(props) {
return {
render(props, args) {
return <div>Hello {props.firstName}</div>;
},
shouldUpdate(newProps, oldProps) {
return newProps.firstName !== oldProps.firstName;
},
};
}
By defining the error() function, Forgo lets you catch errors in child components (at any level, and not necessarily immediate children).
// Here's a component which throws an error.
function BadComponent() {
return {
render() {
throw new Error("Some error occurred :(");
},
};
}
// Parent can catch the error by defining the error() function.
function Parent(props) {
return {
render() {
return (
<div>
<BadComponent />
</div>
);
},
error(props, args) {
return (
<p>
Error in {props.name}: {args.error.message}
</p>
);
},
};
}
The most straight forward way to do rerender is by invoking it with args.element
as the only argument - as follows.
function TodoList(props) {
let todos = [];
return {
render(props, args) {
function addTodos(text) {
todos.push(text);
rerender(args.element);
}
return <div>markup goes here...</div>;
},
};
}
But there are a couple of handy options to rerender, 'newProps' and 'forceRerender'.
newProps let you pass a new set of props while rerendering. If you'd like previous props to be used, pass undefined here.
forceRerender defaults to true, but when set to false skips child component rendering if props haven't changed.
const newProps = { name: "Kai" };
const forceRerender = false;
rerender(args.element, newProps, forceRerender);
Forgo also exports a render method that returns the rendered DOM node that could then be manually mounted.
const { node } = render(<Component />);
window.addEventListener("load", () => {
document.getElementById("root")!.firstElementChild!.replaceWith(node);
});
Forgo Router (forgo-router) is a tiny router for Forgo, and is just around 1KB gzipped. https://github.com/forgojs/forgo-router
Forgo State (forgo-state) is an easy-to-use application state management solution for Forgo (like Redux or MobX), and is less than 1KB gzipped. https://github.com/forgojs/forgo-state
You can try the Todo List app with Forgo on CodeSandbox.
Or if you prefer Typescript, try Forgo TodoList in TypeScript.
There is also an example for using Forgo with forgo-router.
Forgo uses the latest JSX createElement factory changes, so you might need to enable this with Babel. More details here: https://babeljs.io/docs/en/babel-plugin-transform-react-jsx
For your babel config:
{
"plugins": [
[
"@babel/plugin-transform-react-jsx",
{
"throwIfNamespace": false,
"runtime": "automatic",
"importSource": "forgo"
}
]
]
}
If you're using TypeScript, add the following lines to your tsconfig.json file.
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "forgo"
}
}
You can reach out to me via twitter or email. If you find issues, please file a bug on Github.
FAQs
Forgo is a 4KB library that makes it super easy to create modern web apps using JSX (like React).
The npm package forgo receives a total of 3 weekly downloads. As such, forgo popularity was classified as not popular.
We found that forgo demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.